package com.beiding.workordersystem.main.utils;

import com.beiding.workordersystem.main.entity.Option;
import com.beiding.workordersystem.main.entity.OptionItem;
import com.beiding.workordersystem.main.option.OptionAble;
import com.beiding.workordersystem.main.option.TreeAble;
import lombok.Data;
import org.springframework.cglib.beans.BeanMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class OptionUtils {

    public static Option mapToOption(Map<String, Object> map, Class<? extends OptionAble> c) {
        try {
            //首先创建一个实体
            BeanMap beanMap = BeanMap.create(c.newInstance());
            //只能将非空的值放入
            map.forEach((k, v) -> {
                if (k != null && v != null) {
                    beanMap.put(k, v);
                }
            });
            //获取实体
            OptionAble bean = (OptionAble) beanMap.getBean();
            //实体再处理为option
            return beanToOption(bean);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static List<OptionAble> optionsToBeans(List<Option> options) {
        List<OptionAble> optionAbles = new ArrayList<>();
        for (Option option : options) {
            optionAbles.add(optionToBean(option));
        }
        return optionAbles;
    }

    public static OptionAble optionToBean(Option option) {

        List<OptionItem> list = option.getItems();

        //返回一个空白对象
        if (list == null) {
            Class type = option.getType();
            if (type == null) {
                try {
                    type = Class.forName(option.getTypeName());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            Class<?>[] classes = type.getInterfaces();
            boolean it = false;
            for (Class<?> aClass : classes) {
                if (aClass == TreeAble.class) {
                    it = true;
                    break;
                }
            }
            if (it) {
                return new EmptyTreeNode(option.getId(), option.getPid(), option.getHierarchy(), null);
            } else {
                return new EmptyOption(option.getId());
            }
        }
        try {
            OptionAble r = (OptionAble) Class.forName(option.getTypeName()).newInstance();
            BeanMap map = BeanMap.create(r);
            for (OptionItem item : list) {
                map.put(item.getTheKey(), item.getValue());
            }
            r.setId(option.getId());
            if (r instanceof TreeAble) {
                ((TreeAble) r).setPid(option.getPid());
                ((TreeAble) r).setHierarchy(option.getHierarchy());
            }
            return (OptionAble) map.getBean();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Option beanToOption(OptionAble bean) {
        //将实体重新处理成Option
        BeanMap map = BeanMap.create(bean);
        List<OptionItem> items = new ArrayList<>();
        Option option = new Option();
        map.forEach((k, v) -> {
            if (v == null) {
                return;
            }
            OptionItem item = new OptionItem();
            item.setTheKey((String) k);
            item.setValue(v);
            items.add(item);
        });

        option.setType(bean.getClass());
        option.setTypeName(bean.getClass().getName());
        option.setItems(items);
        option.setId(bean.getId());
        if (bean instanceof TreeAble) {
            option.setHierarchy(((TreeAble) bean).getHierarchy());
            option.setPid(((TreeAble) bean).getPid());
        }
        return option;
    }

    @Data
    public static class EmptyTreeNode extends EmptyOption implements TreeAble {
        private List children;
        private Integer hierarchy;
        private String pid;

        public EmptyTreeNode(String id, String pid, Integer hierarchy, List children) {
            super(id);
            this.children = children;
            this.hierarchy = hierarchy;
            this.pid = pid;
        }
    }

    @Data
    public static class EmptyOption implements OptionAble {
        private String id;

        public EmptyOption(String id) {
            this.id = id;
        }
    }

}
